package com.tin.triper.UI;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.tin.triper.Constants;
import com.tin.triper.R;
import com.tin.triper.Background.RecorderService;
import com.tin.triper.Background.RecorderService.RecordBinder;
import com.tin.triper.Data.LocationProvider;
import com.tin.triper.Data.Resources;
import com.tin.triper.Data.TripOverlay;
import com.tin.triper.Data.TripPoint;
import com.tin.triper.Data.TriperItemizedOverlay;
import com.tin.triper.Helper.Formating;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class RecordActivity extends MapActivity {
	private MapView mapView;
	private TextView longitude;
	private TextView latitude;
	private TextView time;
	private TextView speed;
	private Button addText;
	private Button addPhoto;
	private Button addVoice;
	private Button addVideo;
	private MapController mapController;
	private List<Overlay> mapOverlays;
	private RecorderService serviceBinder;
	boolean isBound = false;
	private List<TripPoint> pointList = new ArrayList<TripPoint>();
	private List<Resources> resourcesList = new ArrayList<Resources>();
	private int lastDrawnPoint;
	LocationObserver locationObserver;
	int activityMode = -1;

	SharedPreferences prefs;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.maps);
		activityMode = getIntent().getExtras().getInt(Constants.ACTIVITY_MODE);
		mapView = (MapView) findViewById(R.id.mapview);
		longitude = (TextView) findViewById(R.id.longitude);
		latitude = (TextView) findViewById(R.id.latitude);
		time = (TextView) findViewById(R.id.time);
		speed = (TextView) findViewById(R.id.speed);
		mapView.setBuiltInZoomControls(true);
		mapOverlays = mapView.getOverlays();
		addText = (Button) findViewById(R.id.recorder_add_text);
		addPhoto = (Button) findViewById(R.id.recorder_add_photo);
		addVideo = (Button) findViewById(R.id.recorder_add_video);
		addVoice = (Button) findViewById(R.id.recorder_add_voice);
		prefs = getSharedPreferences(Constants.PREFS_NAME, MODE_PRIVATE);
		mapOverlays = mapView.getOverlays();
		mapController = mapView.getController();
		mapController.setZoom(15);
		lastDrawnPoint = 0;
		time.setText(getString(R.string.common_time) + ": ");
		longitude.setText(getString(R.string.common_longitude) + ": ");
		latitude.setText(getString(R.string.common_latitude) + ": ");
		speed.setText(getString(R.string.common_speed) + ": ");
		addVoice.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				addResource(1);
			}
		});
		addPhoto.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				addResource(2);
			}
		});
		addVideo.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				addResource(3);
			}
		});
		addText.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				addResource(0);
			}
		});
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	@Override
	protected void onStart() {
		super.onStart();
		Intent intent = new Intent(this, RecorderService.class);
		bindService(intent, connection, Context.BIND_AUTO_CREATE);
	}

	@Override
	protected void onResume() {
		super.onResume();
		mapView.invalidate();
		drawTripPath();
		drawResourcesonMap();
		locationObserver = new LocationObserver();
		this.getApplicationContext()
				.getContentResolver()
				.registerContentObserver(LocationProvider.CONTENT_URI_LOCATION,
						true, locationObserver);
		if (activityMode == 0) {
			addText.performClick();
			activityMode = -1;
		}
		if (activityMode == 1) {
			addVoice.performClick();
			activityMode = -1;
		}
		if (activityMode == 2) {
			addPhoto.performClick();
			activityMode = -1;
		}
		if (activityMode == 3) {
			addVideo.performClick();
			activityMode = -1;
		}
		
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (locationObserver != null) {
			this.getApplicationContext().getContentResolver()
					.unregisterContentObserver(locationObserver);
			locationObserver = null;
		}
	}

	@Override
	protected void onStop() {
		super.onStop();
		if (isBound) {
			unbindService(connection);
			isBound = false;
		}
	}

	private ServiceConnection connection = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName className, IBinder service) {
			RecordBinder binder = (RecordBinder) service;
			serviceBinder = binder.getService();
			isBound = true;
		}

		@Override
		public void onServiceDisconnected(ComponentName arg0) {
			isBound = false;
		}
	};

	private void drawResources() {
		for (int i = 0; i < resourcesList.size(); i++) {
			drawResoruce(resourcesList.get(i).locationId,
					resourcesList.get(i).type);
		}
	}

	private void drawResoruce(int locationId, int resourceType) {
		Bitmap resource = null;
		if (resourceType == 0) {
			resource = BitmapFactory.decodeResource(getResources(),
					R.drawable.text);
		} else if (resourceType == 1) {
			resource = BitmapFactory.decodeResource(getResources(),
					R.drawable.voice);
		} else if (resourceType == 2) {
			resource = BitmapFactory.decodeResource(getResources(),
					R.drawable.photo);
		} else {
			// video
			resource = BitmapFactory.decodeResource(getResources(),
					R.drawable.video);
		}
		if (resource != null) {
			for (int i = 0; i < pointList.size(); i++)
				if (pointList.get(i).id == locationId) {
					mapView.getOverlays().add(
							new TripOverlay(pointList.get(i), 4, resource));
					break;
				}
		}
	}

	private void drawResourcesonMap() {
		resourcesList.clear();
		Cursor resourcesCursor = getContentResolver().query(
				LocationProvider.CONTENT_URI_RESOURCES,
				new String[] { LocationProvider.RESOURCE_ID,
						LocationProvider.LOCATION_ID,
						LocationProvider.RESOURCE_FILENAME,
						LocationProvider.RESOURCE_TYPE },
				LocationProvider.TRIP_ID + " ='"
						+ prefs.getInt(Constants.RECORDED_TRIP_ID, 0) + "'",
				null, null);
		if (resourcesCursor != null)
			while (resourcesCursor.moveToNext()) {
				Resources res = new Resources();
				res.id = resourcesCursor.getInt(0);
				res.locationId = resourcesCursor.getInt(1);
				res.fileName = resourcesCursor.getString(2);
				res.type = resourcesCursor.getInt(3);
				resourcesList.add(res);
			}
		resourcesCursor.close();
		drawResources();
		for (int i = 0; i < resourcesList.size(); i++)
			for (int l = 0; l < pointList.size(); l++) {
				if (resourcesList.get(i).locationId == pointList.get(l).id)
					pointList.get(l).gotResouce = true;
			}

	}

	private void drawTripPath() {
		mapOverlays.clear();
		Cursor cursor = getContentResolver().query(
				LocationProvider.CONTENT_URI_LOCATION,
				new String[] { LocationProvider.LOCATION_LATITUDE,
						LocationProvider.LOCATION_LONGITUDE,
						LocationProvider.LOCATION_TIME,
						LocationProvider.LOCATION_ID },
				LocationProvider.TRIP_ID + " ='"
						+ prefs.getInt(Constants.RECORDED_TRIP_ID, 0) + "'",
				null, LocationProvider.LOCATION_TIME);
		if (cursor != null)
			while (cursor.moveToNext()) {
				TripPoint point = new TripPoint(
						(int) (cursor.getDouble(0) * 1E6),
						(int) (cursor.getDouble(1) * 1E6), cursor.getLong(2),
						cursor.getInt(3));
				pointList.add(point);
			}
		cursor.close();
		if (lastDrawnPoint == 0) {
			if (pointList.size() > 0)
				drawPath(pointList, Color.parseColor("#0F08D3"), mapView, 1);
		} else {
			drawPath(pointList, Color.parseColor("#0F08D3"), mapView,
					lastDrawnPoint);

		}
	}



	public void drawPath(final List<TripPoint> pointList, int color,
			MapView mapView, int startPoint) {
		try {
			GeoPoint startGP = new GeoPoint(pointList.get(0).getLatitudeE6(),
					pointList.get(0).getLongitudeE6());

			mapOverlays.add(new TripOverlay(startGP, startGP, 1));
			GeoPoint gp1 = startGP;
			GeoPoint gp2;
			if (startPoint > 1)
				gp2 = pointList.get(startPoint);
			else
				gp2 = startGP;

			for (int i = startPoint; i < pointList.size(); i++) // the last one
																// would be
																// crash
			{

				gp1 = gp2;

				if (pointList.size() >= 2) {
					gp2 = pointList.get(i);
					mapOverlays.add(new TripOverlay(gp1, gp2, 2, color));
					Log.d("mapview",
							"draw:" + gp1.getLatitudeE6() + "/"
									+ gp1.getLongitudeE6() + " TO "
									+ gp2.getLatitudeE6() + "/"
									+ gp2.getLongitudeE6());

				}
				Log.d("mapview", "pair:" + pointList.get(i));
			}
			mapOverlays.add(new TripOverlay(gp2, new GeoPoint(pointList.get(
					pointList.size() - 1).getLatitudeE6(), pointList.get(
					pointList.size() - 1).getLongitudeE6()), 3));

		} catch (NumberFormatException e) {
			Log.e("mapview", "Cannot draw route.", e);
		}
		if (pointList.size() > 1)
			lastDrawnPoint = pointList.size();

		final Date date = new Date();
		date.setTime(pointList.get(pointList.size() - 1).time);
		time.post(new Runnable() {

			@Override
			public void run() {
				mapController.animateTo(new GeoPoint(pointList.get(
						pointList.size() - 1).getLatitudeE6(), pointList.get(
						pointList.size() - 1).getLongitudeE6()));
				SimpleDateFormat formatter = new SimpleDateFormat(
						"yyyy.MM.dd 'at' H:mm:ss ");
				time.setText(getString(R.string.common_time) + ": "
						+ formatter.format(date));
				longitude.setText(getString(R.string.common_longitude) + ": "
						+ pointList.get(pointList.size() - 1).getLongitudeE6()
						/ 1E6 + "");
				latitude.setText(getString(R.string.common_latitude) + ": "
						+ pointList.get(pointList.size() - 1).getLatitudeE6()
						/ 1E6 + "");
				speed.setText(getString(R.string.common_speed) + ": "
						+ Formating.countSpeed(pointList, pointList.size() - 1));
			}
		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.record_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection

		switch (item.getItemId()) {
		case R.id.record_stop:
			serviceBinder.stopRecording();
			prefs.edit().putBoolean(Constants.IS_RECORDING, false).commit();
			prefs.edit().putString(Constants.TRIP_NAME, "").commit();
			prefs.edit().putString(Constants.RECRODED_TRIP_NAME, "").commit();
			prefs.edit().putInt(Constants.LAST_INSERTED_LOCATION_ID, 0)
					.commit();
			finish();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void addResource(int item) {
		if (prefs.getInt(Constants.LAST_INSERTED_LOCATION_ID, 0) == 0) {
			new UpdateLocationForResourceTask(RecordActivity.this, item)
					.execute();
		} else {
			Date dateNow = new Date();
			if (pointList.get(pointList.size() - 1).gotResouce
					|| dateNow.getTime()
							- prefs.getLong(
									Constants.LAST_INSERTED_LOCATION_TIME, 0) > 60000) {
				new UpdateLocationForResourceTask(RecordActivity.this, item)
						.execute();
			} else {
				switch (item) {
				case 2:
					addImage();
					break;
				case 0:
					addText();
					break;
				case 1:
					addVoice();
					break;
				case 3:
					addVideo();
					break;
				default:
					break;
				}
			}
		}
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == Constants.TEXT_ACTIVITY) {
			if (resultCode == RESULT_OK) {
				TriperItemizedOverlay resource = new TriperItemizedOverlay(this
						.getResources().getDrawable(R.drawable.text));
				OverlayItem overlayitem = new OverlayItem(
						pointList.get(pointList.size() - 1),
						getString(R.string.common_text), "");
				resource.addOverlay(overlayitem);
				mapOverlays.add(resource);
			}
		} else if (requestCode == Constants.VOICE_ACTIVITY) {
			if (resultCode == RESULT_OK) {
				TriperItemizedOverlay resource = new TriperItemizedOverlay(this
						.getResources().getDrawable(R.drawable.voice));
				OverlayItem overlayitem = new OverlayItem(
						pointList.get(pointList.size() - 1),
						getString(R.string.common_voice), "");
				resource.addOverlay(overlayitem);
				mapOverlays.add(resource);
			}
		} else if (requestCode == Constants.IMAGE_ACTIVITY) {
			if (resultCode == RESULT_OK) {
				TriperItemizedOverlay resource = new TriperItemizedOverlay(this
						.getResources().getDrawable(R.drawable.photo));
				OverlayItem overlayitem = new OverlayItem(
						pointList.get(pointList.size() - 1),
						getString(R.string.common_photo), "");
				resource.addOverlay(overlayitem);
				mapOverlays.add(resource);
			}
		} else if (requestCode == Constants.VIDEO_ACTIVITY) {
			if (resultCode == RESULT_OK) {
				TriperItemizedOverlay resource = new TriperItemizedOverlay(this
						.getResources().getDrawable(R.drawable.video));
				OverlayItem overlayitem = new OverlayItem(
						pointList.get(pointList.size() - 1),
						getString(R.string.common_video), "");
				resource.addOverlay(overlayitem);
				mapOverlays.add(resource);
			}
		}
	}

	protected void addVideo() {
		Intent intent = new Intent(RecordActivity.this, VideoActivity.class);
		intent.putExtra(Constants.ACTIVITY_MODE, 0);
		startActivityForResult(intent, Constants.VIDEO_ACTIVITY);
	}

	protected void addVoice() {
		Intent intent = new Intent(RecordActivity.this, VoiceActivity.class);
		intent.putExtra(Constants.ACTIVITY_MODE, 0);
		startActivityForResult(intent, Constants.VOICE_ACTIVITY);
	}

	protected void addText() {
		Intent intent = new Intent(RecordActivity.this, TextActivity.class);
		intent.putExtra(Constants.ACTIVITY_MODE, 0);
		startActivityForResult(intent, Constants.TEXT_ACTIVITY);
	}

	protected void addImage() {
		Intent intent = new Intent(RecordActivity.this, ImageActivity.class);
		intent.putExtra(Constants.ACTIVITY_MODE, 0);
		startActivityForResult(intent, Constants.IMAGE_ACTIVITY);
	}

	private class LocationObserver extends ContentObserver {

		public LocationObserver() {
			super(null);
		}

		@Override
		public void onChange(boolean selfChange) {
			super.onChange(selfChange);
			drawTripPath();
		}

		@Override
		public boolean deliverSelfNotifications() {
			return true;
		}

	}

	private class UpdateLocationForResourceTask extends
			AsyncTask<Void, Void, Boolean> {
		int locationId;
		ProgressDialog dialog;
		int option;
		Context context;
		boolean isGettingLocationUpdate = false;
		Date date;

		public UpdateLocationForResourceTask(Context context, int option) {
			this.locationId = prefs.getInt(Constants.LAST_INSERTED_LOCATION_ID,
					0);
			this.context = context;
			dialog = new ProgressDialog(context);
			this.option = option;
		}

		protected void onPreExecute() {
			dialog.setMessage(getString(R.string.recorder_info_update_location));
			dialog.setIndeterminate(true);
			dialog.setCancelable(false);
			try {
				dialog.show();
			} catch (Exception e) {
			}
		}

		protected Boolean doInBackground(Void... urls) {
			date = new Date();
			while (locationId == prefs.getInt(
					Constants.LAST_INSERTED_LOCATION_ID, 0)) {
				if (!isGettingLocationUpdate)
					publishProgress();
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (new Date().getTime() - date.getTime() > 60000)
					return false;
			}
			return true;
		}

		protected void onProgressUpdate(Void... progress) {
			if (isBound) {
				serviceBinder.updateLocation();
				isGettingLocationUpdate = true;
			}
		}

		protected void onPostExecute(Boolean result) {
			try {
				dialog.dismiss();
			} catch (Exception e) {
			}
			if (result) {
				switch (option) {
				case 2:
					addImage();
					break;
				case 0:
					addText();
					break;
				case 1:
					addVoice();
					break;
				case 3:
					addVideo();
					break;
				default:
					break;
				}
			} else {
				Toast.makeText(context,
						getString(R.string.error_message_getting_location),
						Toast.LENGTH_SHORT).show();
			}
		}
	}

}
